package redis

import (
	"errors"
	"github.com/go-redis/redis"
	"math"
	"strconv"
	"time"
)

// 本项目使用简化版的投票分数
/* 投票的几种情况
direction=1时,有两种情况:
	1.之前没有投过票，现在投赞成票   --> 更新分数和投票记录  差值的绝对值:1  +432
	2.之前投反对票，现在改投赞成票   --> 更新分数和投票记录  差值的绝对值:2  +432*2
direction=0时,有两种情况:
	1.之前投过反对票，现在要取消投票  --> 更新分数和投票记录  差值的绝对值:1  +432
	2.之前投过赞成票，现在要取消投票  --> 更新分数和投票记录  差值的绝对值:1  -432
direction=-1时,有两种情况:
	1.之前没有投过票，现在投反对票    --> 更新分数和投票记录  差值的绝对值:1  -432
	2.之前投过赞成票。现在改投反对票  --> 更新分数和投票记录  差值的绝对值:2  -432*2


投票的限制:
每个帖子自发表之日起一个星期之内允许用户投票,超过一个星期就不允许再投票了
	1.到期之后将redis中保存的赞成票数及反对票数存储到mysql表中
	2.到期之后删除那个 KeyPostVotedZSetPrefix
*/

const (
	oneWeekInSeconds = 7 * 24 * 3600
	scorePerVote     = 432
)

var (
	ErrVoteTimeExpire = errors.New("投票时间已过")
	ErrVoteRepeated   = errors.New("不允许重复投票")
)

func CreatePost(postID, communityID int64) error {
	pipeline := client.TxPipeline()
	//帖子时间
	pipeline.ZAdd(getRedisKey(KeyPostTimeZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: postID,
	})

	//帖子分数
	pipeline.ZAdd(getRedisKey(KeyPostScoreZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: postID,
	})
	//把帖子id加到社区的set
	cKey := getRedisKey(KeyCommunitySetPrefix + strconv.Itoa(int(communityID)))
	pipeline.SAdd(cKey, postID)
	_, err := pipeline.Exec()
	return err

}

// VoteForPost给帖子投票
func VoteForPost(userID string, postID string, value float64) (err error) { //userID:谁； postID:哪个帖子  value:分数
	//去帖子取发布时间,超过一星期不允许再投票
	postTime := client.ZScore(getRedisKey(KeyPostTimeZSet), postID).Val()
	if float64(time.Now().Unix())-postTime > oneWeekInSeconds {
		return ErrVoteTimeExpire
	}
	// 更新帖子分数
	oldValue := client.ZScore(getRedisKey(KeyPostVotedZSetPrefix+postID), userID).Val() //查询当前用户给当前帖子的投票记录
	var direction float64
	if value > oldValue {
		direction = 1
	} else {
		direction = -1
	}
	diff := math.Abs(oldValue - value) //计算两次投票的差值

	_, err = client.ZIncrBy(getRedisKey(KeyPostScoreZSet), diff*direction*scorePerVote, postID).Result()

	// 记录用户为帖子投票的数据
	if value == 0 { //删除该用户的投票记录
		_, err = client.ZRem(getRedisKey(KeyPostVotedZSetPrefix+postID), userID).Result()

	} else {
		_, err = client.ZAdd(getRedisKey(KeyPostVotedZSetPrefix+postID), redis.Z{
			Score:  value, //赞成票还是反对票
			Member: userID,
		}).Result()
	}

	return err
}
